﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Clipper2Lib;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AutoStar.Models
{
    public class Point3D : IEquatable<Point3D>
    {
        public float X { get; }
        public float Y { get; }
        public float Z { get; }

        public Point3D(float x, float y, float z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        public bool Equals(Point3D other) =>
            Math.Abs(X - other.X) < 1e-5f &&
            Math.Abs(Y - other.Y) < 1e-5f &&
            Math.Abs(Z - other.Z) < 1e-5f;

        public override int GetHashCode() => HashCode.Combine(X, Y, Z);
    }

    public class Triangle3D
    {
        public Point3D[] Vertices { get; }
        public float MinZ { get; }
        public float MaxZ { get; }

        public Triangle3D(Point3D p1, Point3D p2, Point3D p3)
        {
            // 过滤异常三角形（处理模型数据错误）
            if (IsValidTriangle(p1, p2, p3))
            {
                Vertices = new[] { p1, p2, p3 };
                MinZ = Math.Min(p1.Z, Math.Min(p2.Z, p3.Z));
                MaxZ = Math.Max(p1.Z, Math.Max(p2.Z, p3.Z));
            }
            else
            {
                Vertices = Array.Empty<Point3D>();
                MinZ = float.MaxValue;
                MaxZ = float.MinValue;
            }
        }

        private static bool IsValidTriangle(Point3D p1, Point3D p2, Point3D p3)
        {
            // 过滤包含异常值的三角形
            const float validRange = 1e4; // 根据实际模型尺寸调整
            return IsValidPoint(p1) && IsValidPoint(p2) && IsValidPoint(p3) &&
                   Math.Abs(p1.X) < validRange && Math.Abs(p2.X) < validRange && Math.Abs(p3.X) < validRange &&
                   Math.Abs(p1.Y) < validRange && Math.Abs(p2.Y) < validRange && Math.Abs(p3.Y) < validRange;
        }
    }

    public class Model3D
    {
        public List<Triangle3D> Triangles { get; } = new List<Triangle3D>();
        public float ModelHeight { get; set; }
        public float BaseZ { get; set; }
    }

    public class PathGenerator
    {
        private const float Epsilon = 1e-5f;
        private const float SnapThreshold = 0.01f; // 点合并阈值

        public List<List<Point3D>> GeneratePrintPaths(Model3D model, float layerHeight)
        {
            var layers = PrepareLayers(model, layerHeight);
            return layers.Select(ProcessLayer).ToList();
        }

        private List<List<Point3D>> PrepareLayers(Model3D model, float layerHeight)
        {
            float minZ = model.BaseZ;
            float maxZ = model.BaseZ + model.ModelHeight;
            int layerCount = (int)Math.Ceiling((maxZ - minZ) / layerHeight);

            return Enumerable.Range(0, layerCount)
                .Select(i => new
                {
                    LayerIndex = i,
                    CurrentZ = minZ + i * layerHeight
                })
                .Select(x => model.Triangles
                    .Where(t => x.CurrentZ >= t.MinZ - Epsilon && x.CurrentZ <= t.MaxZ + Epsilon)
                    .SelectMany(t => GetIntersections(t, x.CurrentZ))
                    .Where(IsValidPoint)
                    .ToList())
                .Select(FindContours)
                .ToList();
        }

        private List<Point3D> GetIntersections(Triangle3D tri, float z)
        {
            var points = new List<Point3D>();
            for (int i = 0; i < 3; i++)
            {
                var a = tri.Vertices[i];
                var b = tri.Vertices[(i + 1) % 3];

                if (Math.Abs(a.Z - z) < Epsilon && Math.Abs(b.Z - z) < Epsilon)
                {
                    if (IsValidPoint(a)) points.Add(a);
                    if (IsValidPoint(b)) points.Add(b);
                    continue;
                }

                if (Math.Sign(a.Z - z) == Math.Sign(b.Z - z)) continue;

                float t = (z - a.Z) / (b.Z - a.Z);
                var pt = new Point3D(
                    a.X + t * (b.X - a.X),
                    a.Y + t * (b.Y - a.Y),
                    z
                );

                if (IsValidPoint(pt)) points.Add(pt);
            }
            return points.Count % 2 == 0 ? points : new List<Point3D>();
        }

        private List<List<Point3D>> FindContours(List<Point3D> points)
        {
            var edges = BuildEdgeGraph(points);
            return TraceContours(edges);
        }

        private Dictionary<Point3D, List<Point3D>> BuildEdgeGraph(List<Point3D> points)
        {
            var graph = new Dictionary<Point3D, List<Point3D>>();
            for (int i = 0; i < points.Count; i += 2)
            {
                if (i + 1 >= points.Count) break;
                AddEdge(points[i], points[i + 1]);
                AddEdge(points[i + 1], points[i]);
            }
            return graph;

            void AddEdge(Point3D a, Point3D b)
            {
                if (!graph.ContainsKey(a)) graph[a] = new List<Point3D>();
                graph[a].Add(b);
            }
        }

        private List<List<Point3D>> TraceContours(Dictionary<Point3D, List<Point3D>> graph)
        {
            var contours = new List<List<Point3D>>();
            var visited = new HashSet<Point3D>();

            foreach (var start in graph.Keys.Where(p => !visited.Contains(p)))
            {
                var contour = new List<Point3D>();
                var current = start;
                Point3D prev = null;

                do
                {
                    visited.Add(current);
                    contour.Add(current);

                    var next = graph[current]
                        .FirstOrDefault(n => n != prev && !visited.Contains(n));

                    prev = current;
                    current = next;
                } while (current != null && !current.Equals(start));

                if (contour.Count > 2)
                {
                    contour.Add(contour[0]); // 闭合轮廓
                    contours.Add(OptimizeContour(contour));
                }
            }
            return contours;
        }

        private List<Point3D> OptimizeContour(List<Point3D> contour)
        {
            // 点合并和简化
            var optimized = new List<Point3D>();
            Point3D last = null;
            foreach (var p in contour)
            {
                if (last == null || !IsNear(last, p, SnapThreshold))
                {
                    optimized.Add(p);
                    last = p;
                }
            }
            return optimized;
        }

        private static bool IsNear(Point3D a, Point3D b, float threshold) =>
            Math.Abs(a.X - b.X) < threshold &&
            Math.Abs(a.Y - b.Y) < threshold;

        private static bool IsValidPoint(Point3D p) =>
            !float.IsNaN(p.X) && !float.IsInfinity(p.X) &&
            !float.IsNaN(p.Y) && !float.IsInfinity(p.Y) &&
            !float.IsNaN(p.Z) && !float.IsInfinity(p.Z);
    }
}
